﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Raven.Client;

namespace Rabbit.Logic
{
    public class RabbitUse
    {
        public static List<Product> GetProductList(IDocumentStore store)
        {
            List<Product> items = null;
            using (IDocumentSession session = store.OpenSession())
            {
                items = session.Query<Product>().ToList();
            }
            return items;
        }

        public static List<Product> GetProductList(IDocumentStore store, string shopId)
        {
            List<Product> items = null;
            using (IDocumentSession session = store.OpenSession())
            {
                items = session.Query<Product>().Where(x => x.ShopId == shopId).ToList();
            }
            return items;
        }

        public static List<DiliveryStrategy> GetDiliveryStrategyList(IDocumentStore store, string shopId)
        {
            List<DiliveryStrategy> items = null;
            using (IDocumentSession session = store.OpenSession())
            {
                items = session.Query<DiliveryStrategy>().Where(x => x.ShopId == shopId).ToList();
            }
            return items;
        }

        public static List<Customer> GetCustomerList(IDocumentStore store)
        {
            List<Customer> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Customer>().ToList();
            }
            return items;
        }

        public static List<Order> GetOrderList(IDocumentStore store)
        {
            List<Order> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Order>().ToList();
            }
            return items;
        }


        #region GetById

        public static Order GetOrderById(IDocumentStore store, string id)
        {
            Order item = null;
            using (IDocumentSession session = store.OpenSession())
            {
                item = session.Load<Order>(id);
            }
            return item;
        }

        public static OrderLog GetOrderLogByOrderId(IDocumentStore store, string oid)
        {
            OrderLog item = null;
            using (IDocumentSession session = store.OpenSession())
            {
                Order order = session.Load<Order>(oid);
                if (!string.IsNullOrEmpty(order.OrderLogId))
                {
                    item = session.Load<OrderLog>(order.OrderLogId);
                }
            }
            return item;
        }

        public static OrderLog MakeOrderLogReady(IDocumentStore store, string orderId)
        {
            OrderLog log;
            using (IDocumentSession session = store.OpenSession())
            {
                Order order = session.Load<Order>(orderId);
                if (string.IsNullOrEmpty(order.OrderLogId))
                {
                    log = new OrderLog();
                    log.OrderId = order.Id;
                    log.LogList = new List<string>();

                    session.Store(log);
                    order.OrderLogId = log.Id;
                    session.Store(order);
                    session.SaveChanges();
                }
                else
                {
                    log = session.Load<OrderLog>(order.OrderLogId);
                }
            }
            return log;
        }

        public static Product GetProductById(IDocumentStore store, string id)
        {
            Product item = null;
            using (IDocumentSession session = store.OpenSession()) 
            {
                item = session.Load<Product>(id);
            }
            return item;
        }

        public static DiliveryStrategy GetDiliveryStrategyById(IDocumentStore store, string id)
        {
            DiliveryStrategy item = null;
            using (IDocumentSession session = store.OpenSession()) 
            {
                item = session.Load<DiliveryStrategy>(id);
            }
            return item;
        }

        public static Customer GetCustomerById(IDocumentStore store, string id)
        {
            Customer item = null;
            using (IDocumentSession session = store.OpenSession())  
            {
                item = session.Load<Customer>(id);
            }
            return item;
        }

        public static ProductSnap GetProductSnapBySnapIndex(IDocumentStore store, string id)
        {
            ProductSnap item = null;
            using (IDocumentSession session = store.OpenSession())
            {
                item = session.Query<ProductSnap>().FirstOrDefault(x => x.SnapIndex == id);
            }
            return item;
        }

        public static CustomerOrderMapping GetCustomerOrderMappingById(IDocumentStore store, string id)
        {
            CustomerOrderMapping item = null;
            using (IDocumentSession session = store.OpenSession())
            {
                item = session.Load<CustomerOrderMapping>(id);
            }
            return item;
        }

        public static ShopOrderMapping GetShopOrderMappingById(IDocumentStore store, string id)
        {
            ShopOrderMapping item = null;
            using (IDocumentSession session = store.OpenSession())
            {
                item = session.Load<ShopOrderMapping>(id);
            }
            return item;
        }

        //no use
        public static CustomerOrderMapping GetCustomerOrderMappingByCustomerId(IDocumentStore store, string id)
        {
            CustomerOrderMapping item = null;
            using (IDocumentSession session = store.OpenSession())
            {
                item = session.Query<CustomerOrderMapping>().FirstOrDefault(x => x.CustomerId == id);
            }
            return item;
        }

        public static Shop GetShopById(IDocumentStore store, string id)
        {
            Shop item = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                item = session.Load<Shop>(id);
            }
            return item;
        }
        public static Shop GetShopByShopId(IDocumentStore store, string id)
        {
            Shop item = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                item = session.Query<Shop>().FirstOrDefault(x => x.ShopId == id);
            }
            return item;
        }
        public static ShipRule GetShipRuleByShopId(IDocumentStore store, string id)
        {
            ShipRule item = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                item = session.Query<ShipRule>().FirstOrDefault(x => x.ShopId == id);
            }
            return item;
        }
        public static ShopIdentity GetShopIdentityById(IDocumentStore store, string id)
        {
            ShopIdentity item = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                item = session.Load<ShopIdentity>(id);
            }
            return item;
        }

        public static bool DeleteProductById(IDocumentStore store, string id)
        {
            Product item = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                item = session.Load<Product>(id);
                if (item == null) return false;
                session.Delete(item);
                session.SaveChanges();
            }
            return true;
        }

        public static bool DeleteDiliveryStrategyById(IDocumentStore store, string id)
        {
            DiliveryStrategy item = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                item = session.Load<DiliveryStrategy>(id);
                if (item == null) return false;
                session.Delete(item);
                session.SaveChanges();
            }
            return true;
        }

        public static bool DeleteAddressById(IDocumentStore store, Customer customer,int id)
        {
            using (IDocumentSession session = store.OpenSession()) 
            {
                customer.AddressList.RemoveAt(id);
                session.SaveChanges();
            }
            return true;
        }

        

#endregion

        public static IQueryable<Customer> GetCustomerByName(IDocumentStore store, string name)
        {
            IQueryable<Customer> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Customer>().Where(x => x.Name == name);
            }
            return items;
        }
        public static IQueryable<Shop> GetShopByName(IDocumentStore store, string name)
        {
            IQueryable<Shop> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Shop>().Where(x => x.Name == name);
            }
            return items;
        }
        public static IQueryable<Shop> GetShopByNickName(IDocumentStore store, string name)
        {
            IQueryable<Shop> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Shop>().Where(x => x.NickName == name);
            }
            return items;
        }

        public static IQueryable<ShopIdentity> GetShopIdentityByName(IDocumentStore store, string name)
        {
            IQueryable<ShopIdentity> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<ShopIdentity>().Where(x => x.Name == name);
            }
            return items;
        }

        public static IQueryable<Customer> GetCustomerByCellPhone(IDocumentStore store, string cellphone)
        {
            IQueryable<Customer> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Customer>().Where(x => x.CellPhone == cellphone);
            }
            return items;
        }
        public static IQueryable<Shop> GetShopByCellPhone(IDocumentStore store, string cellphone)
        {
            IQueryable<Shop> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Shop>().Where(x => x.CellPhone == cellphone);
            }
            return items;
        }
        public static IQueryable<ShopIdentity> GetShopIdentityByCellPhone(IDocumentStore store, string cellphone)
        {
            IQueryable<ShopIdentity> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<ShopIdentity>().Where(x => x.CellPhone == cellphone);
            }
            return items;
        }

        public static IQueryable<Customer> GetCustomerByMail(IDocumentStore store, string mail)
        {
            IQueryable<Customer> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Customer>().Where(x => x.Mail == mail);
            }
            return items;
        }
        public static IQueryable<Shop> GetShopByMail(IDocumentStore store, string mail)
        {
            IQueryable<Shop> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<Shop>().Where(x => x.Mail == mail);
            }
            return items;
        }
        public static IQueryable<ShopIdentity> GetShopIdentityByMail(IDocumentStore store, string mail)
        {
            IQueryable<ShopIdentity> items = null;
            using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
            {
                items = session.Query<ShopIdentity>().Where(x => x.Mail == mail);
            }
            return items;
        }

        public static string AddProduct(IDocumentStore store, Product item)
        {
            string msg = null;
            ValidationResult result = ValidateProduct(item);
            if (result==ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
                {
                    item.LastModifiedDate = DateTime.Now;
                    session.Store(item);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }
            
            return msg;
        }

        public static string AddProductSnap(IDocumentStore store, ProductSnap item)
        {
            string msg = null;
            ValidationResult result = ValidateProductSnap(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession())
                {
                    session.Store(item);
                    List<ProductSnap> productSnaps = session.Query<ProductSnap>().Where(x => x.SnapIndex == item.SnapIndex).ToList();
                    if (productSnaps.Count > 1)
                    {
                        session.Delete(item);
                    }
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }

        public static string AddCustomerOrderMapping(IDocumentStore store, CustomerOrderMapping item)
        {
            string msg = null;
            ValidationResult result = ValidateCustomerOrderMapping(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession())
                {
                    session.Store(item);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }

        public static string AddShopOrderMapping(IDocumentStore store, ShopOrderMapping item)
        {
            string msg = null;
            ValidationResult result = ValidateShopOrderMapping(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession())
                {
                    session.Store(item);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }

        public static string AddDiliveryStrategy(IDocumentStore store, DiliveryStrategy item)
        {
            string msg = null;
            ValidationResult result = ValidateDiliveryStrategy(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession()) 
                {
                    session.Store(item);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }
        public static string AddShipDiscount(IDocumentStore store, ShipDiscount item)
        {
            string msg = null;
            ValidationResult result = ValidateShipDiscount(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession())  
                {
                    session.Store(item);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }

        public static string AddShipRule(IDocumentStore store, ShipRule item)
        {
            string msg = null;
            ValidationResult result = ValidateShipRule(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
                {
                    session.Store(item);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }

        public static ValidationResult ValidateProduct(Product item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            if (string.IsNullOrEmpty(item.Name))
            {
                result.ErrorMessage = "Product name is required.";
                return result;
            }

            if (item.PricePerUnit<=0)
            {
                result.ErrorMessage = "Price wrong.";
                return result;
            }

            return ValidationResult.Success;
        }

        public static ValidationResult ValidateProductSnap(ProductSnap item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            if (string.IsNullOrEmpty(item.Name))
            {
                result.ErrorMessage = "Product name is required.";
                return result;
            }

            if (item.PricePerUnit <= 0)
            {
                result.ErrorMessage = "Price wrong.";
                return result;
            }

            return ValidationResult.Success;
        }

        public static ValidationResult ValidateCustomerOrderMapping(CustomerOrderMapping item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            if (string.IsNullOrEmpty(item.CustomerId))
            {
                result.ErrorMessage = "CustomerId is required.";
                return result;
            }

            if (item.OrderIdList==null)
            {
                result.ErrorMessage = "OrderIdList  is required.";
                return result;
            }

            return ValidationResult.Success;
        }

        public static ValidationResult ValidateShopOrderMapping(ShopOrderMapping item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            if (string.IsNullOrEmpty(item.ShopId))
            {
                result.ErrorMessage = "ShopId is required.";
                return result;
            }

            if (item.OrderIdList == null)
            {
                result.ErrorMessage = "OrderIdList  is required.";
                return result;
            }

            return ValidationResult.Success;
        }

        public static ValidationResult ValidateDiliveryStrategy(DiliveryStrategy item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }
            if (string.IsNullOrEmpty(item.StrategyName))
            {
                result.ErrorMessage = "StrategyName is required.";
                return result;
            }

            if (item.Cost < 0)
            {
                result.ErrorMessage = "Price wrong.";
                return result;
            }

            return ValidationResult.Success;
        }
        public static ValidationResult ValidateShipDiscount(ShipDiscount item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            if (item.FreeShipAt < 0)
            {
                result.ErrorMessage = "Price wrong.";
                return result;
            }

            return ValidationResult.Success;
        }
        public static ValidationResult ValidateShipRule(ShipRule item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            return ValidationResult.Success;
        }


        public static string AddOrUpdateCustomer(IDocumentStore store, Customer item)
        {
            string msg = null;
            ValidationResult result = ValidateCustomer(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
                {
                    session.Store(item);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }

        //public static string AddOrder(IDocumentStore store, Order item)
        //{
        //    string msg = null;
        //    ValidationResult result = ValidateOrder(item);
        //    if (result == ValidationResult.Success)
        //    {
        //        using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
        //        {
        //            session.Store(item);
        //            session.SaveChanges();
        //        }
        //    }
        //    else
        //    {
        //        msg = result.ErrorMessage;
        //    }

        //    return msg;
        //}

        public static ValidationResult ValidateCustomer(Customer item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            //if (!string.IsNullOrEmpty(item.Id))
            //{
            //    result.ErrorMessage = "id not null, may cause override";
            //    return result;
            //}

            if (string.IsNullOrEmpty(item.Name))
            {
                result.ErrorMessage = "Product name is required.";
                return result;
            }

            if (string.IsNullOrEmpty(item.Password))
            {
                result.ErrorMessage = "password is required.";
                return result;
            }

            return ValidationResult.Success;
        }

        

        public static string AddOrUpdateShop(IDocumentStore store, Shop item)
        {
            string msg = null;
            ValidationResult result = ValidateShop(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
                {
                    session.Store(item);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }
        public static ValidationResult ValidateShop(Shop item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            return ValidationResult.Success;
        }

        //special
        public static string AddOrUpdateShopIdentity(IDocumentStore store, ShopIdentity item)
        {
            string msg = null;
            ValidationResult result = ValidateShopIdentity(item);
            if (result == ValidationResult.Success)
            {
                using (IDocumentSession session = store.OpenSession()) // opens a session that will work in context of 'DefaultDatabase'
                {
                    session.Store(item);
                    Shop shop = new Shop();
                    shop.ShopId = item.Id;
                    shop.Location = new Address();
                    session.Store(shop);
                    session.SaveChanges();
                }
            }
            else
            {
                msg = result.ErrorMessage;
            }

            return msg;
        }
        public static ValidationResult ValidateShopIdentity(ShopIdentity item)
        {
            var result = new ValidationResult(string.Empty);

            if (item == null)
            {
                result.ErrorMessage = "cannot be null.";
                return result;
            }

            if (string.IsNullOrEmpty(item.Name))
            {
                result.ErrorMessage = "Product name is required.";
                return result;
            }

            if (string.IsNullOrEmpty(item.Password))
            {
                result.ErrorMessage = "password is required.";
                return result;
            }

            return ValidationResult.Success;
        }

        public static List<ShopCartViewItem> GetShopCartView(IDocumentStore store, Customer customer)
        {
            List<ShopCartViewItem> list=new List<ShopCartViewItem>();
            foreach (ShopCartItem item in customer.Cart)
            {
                using (IDocumentSession session = store.OpenSession()) 
                {
                    Product product = session.Load<Product>(item.ProductId);
                    ShopCartViewItem viewItem = new ShopCartViewItem() {ItemInfo = item, ProductInfo = product};
                    list.Add(viewItem);
                }
            }
            return list;
        }

        public static List<ShopItemFull> GetShopItemFullList(IDocumentStore store, Customer customer)
        {
            List<ShopItemFull> list = new List<ShopItemFull>();
            if (customer.ShopList == null) return list;

            foreach (ShopItem item in customer.ShopList)
            {
                using (IDocumentSession session = store.OpenSession())
                {
                    List<ShopCartItemFull> productAndQuantityList = new List<ShopCartItemFull>();
                    foreach (var productItem in item.CartItemList)
                    {
                        Product product = session.Load<Product>(productItem.ProductId);
                        productAndQuantityList.Add(new ShopCartItemFull() {ProductInfo = product, Quantity = productItem.Quantity});
                    }

                    Shop shop = session.Query<Shop>().FirstOrDefault(x => x.ShopId == item.ShopId);
                    ShopItemFull shopItemFull = new ShopItemFull() {ShopInfo = shop, CartItemList = productAndQuantityList};
                    list.Add(shopItemFull);
                }
            }
            return list;
        }
        public static ShopItemFull GetShopItemFull(IDocumentStore store, Customer customer)
        {
            ShopItemFull result = new ShopItemFull();
            if (customer.PreOrderShopItem == null) return result;

            ShopItem item = customer.PreOrderShopItem;
            using (IDocumentSession session = store.OpenSession())
            {
                List<ShopCartItemFull> productAndQuantityList = new List<ShopCartItemFull>();
                foreach (var productItem in item.CartItemList)
                {
                    Product product = session.Load<Product>(productItem.ProductId);
                    productAndQuantityList.Add(new ShopCartItemFull() { ProductInfo = product, Quantity = productItem.Quantity });
                }

                Shop shop = session.Query<Shop>().FirstOrDefault(x => x.ShopId == item.ShopId);
                result = new ShopItemFull() { ShopInfo = shop, CartItemList = productAndQuantityList };
            }

            return result;
        }

        //deprecated
        public static CartTotal ComputeCartTotal(IDocumentStore store, List<ShopCartItem> cart)
        {
            CartTotal result = new CartTotal();
            using (IDocumentSession session = store.OpenSession())  
            {
                foreach (ShopCartItem shopCartItem in cart)
                {
                    result.TotalNumber += shopCartItem.Quantity;
                    Product product = session.Load<Product>(shopCartItem.ProductId);
                    result.TotalWeight += shopCartItem.Quantity*product.GrossWeight;
                    result.TotalPrice += shopCartItem.Quantity*product.PricePerUnit;
                }
            }
            return result;
        }


        
    }
}
